package com.shchuangzhi.smartguard.core.command;

import com.elvishew.xlog.XLog;
import com.shchuangzhi.smartguard.SharedPref;
import com.shchuangzhi.smartguard.core.Consts;
import com.shchuangzhi.smartguard.core.DBHelper;
import com.shchuangzhi.smartguard.core.Machine;
import com.shchuangzhi.smartguard.core.Notify;
import com.shchuangzhi.smartguard.core.NotifyMessage;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by j_hu on 5/5/17.
 */

public abstract class Command {
    private String name;
    private Notify notifier;
    private DBHelper dbHelper;
    private CommandResult commandResult;

    private static final int CONNECT_TIME_OUT = 3000;
    private static final int READ_TIME_OUT = 3000;
    private static final String COMMAND_HEADER = "x-command";

    public interface CommandHandler {
        boolean handle(InputStream input);
    }

    protected Command(String name) {
        this.name = name;
        this.commandResult = new CommandResult();
        this.commandResult.success();
    }

    protected String getName(){
        return name;
    }
    protected String getURL() {
        return Machine.getInstance().getHostURL();
    }
    protected String getToken() {
        return Machine.getInstance().getName();
    }

    public void setDBHelper(DBHelper dbHelper) { this.dbHelper = dbHelper; }
    public void setNotifier(Notify notifier) { this.notifier = notifier; }

    protected DBHelper getDbHelper() {
        return dbHelper;
    }

    protected abstract OutputStream fill(OutputStream output);
    protected abstract String getType();
    protected abstract CommandHandler getHandler(String commandName);

    protected void raiseError(Exception e) {
        XLog.e("", e);
        commandResult.fail(Consts.COMMAND_HANDLE_ERROR);
    }

    protected void success(Object data) {
        commandResult.success(data);
    }

    protected void notify(NotifyMessage message) {
        if (notifier != null) {
            notifier.notify(message);
        }
    }

    public boolean isAvailable() {
        return true;
    }

//    public boolean networkCheck() {
//        boolean good = false;
//        InputStream in = null;
//        HttpURLConnection conn = null;
//        if (ready()) {
//            try {
//                conn = (HttpURLConnection)new URL(getURL()).openConnection();
//                conn.setConnectTimeout(CONNECT_TIME_OUT);
//                conn.setReadTimeout(READ_TIME_OUT);
//
//                int code = conn.getResponseCode();
//                if (code == 200) {
//                    CommandHandler handler = getHandler(null);
//                    if (handler != null) {
//                        in = conn.getInputStream();
//                        good = handler.handle(in);
//                    }
//                } else {
//                    raiseError(new Exception(
//                            String.format("get url:%s return error code:%d", url, code)));
//                }
//            }catch (Exception e) {
//                XLog.e("", e);
//            }finally {
//                try {
//                    if (in != null) {
//                        in.close();
//                    }
//                }catch(Exception e) {
//                    XLog.e("", e);
//                }
//
//                if (conn != null) {
//                    conn.disconnect();
//                }
//            }
//        }
//        return good;
//    }

    public CommandResult runGet() {
        InputStream in = null;
        OutputStream out = null;
        HttpURLConnection conn = null;
        String url = getURL();
        if (ready()) {
            try {
                commandResult.success();
                conn = (HttpURLConnection)new URL(url).openConnection();
                conn.setConnectTimeout(CONNECT_TIME_OUT);
                conn.setReadTimeout(READ_TIME_OUT);

                int code = conn.getResponseCode();
                if (code == 200) {
                    CommandHandler handler = getHandler(null);
                    if (handler != null) {
                        in = conn.getInputStream();
                        handler.handle(in);
                    }
                } else {
                    raiseError(new Exception(
                            String.format("get url:%s return error code:%d", url, code)));
                }
            }catch (Exception e) {
                raiseError(e);
            }finally {
                if (in != null) {
                    try {
                        in.close();
                    }catch(Exception e) {
                        raiseError(e);
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    }catch(Exception e) {
                        raiseError(e);
                    }
                }
                if (conn != null) {
                    conn.disconnect();
                }
            }
        } else {
            commandResult.fail(Consts.HOST_CONNECT_FAIL);
        }

        return commandResult;
    }

    public CommandResult runPost() {
        InputStream in = null;
        OutputStream out = null;
        HttpURLConnection conn = null;
        String url = getURL();
        if (ready()) {
            try {
                commandResult.success();
                conn = (HttpURLConnection)new URL(url).openConnection();
                conn.setDoInput(true);
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                conn.setUseCaches(false);
                conn.setRequestProperty(COMMAND_HEADER, name);
                conn.setRequestProperty("Content-type", getType());
                conn.setConnectTimeout(CONNECT_TIME_OUT);
                conn.setReadTimeout(READ_TIME_OUT);
                conn.connect();
                out = fill(conn.getOutputStream());
                out.flush();

                int code = conn.getResponseCode();
                if (code == 200) {
                    CommandHandler handler = getHandler(conn.getHeaderField(COMMAND_HEADER));
                    if (handler != null) {
                        in = conn.getInputStream();
                        handler.handle(in);
                    }
                } else {
                    raiseError(new Exception(
                            String.format("post url:%s return error code:%d", url, code)));
                }
            }catch (Exception e) {
                raiseError(e);
            }finally {
                if (in != null) {
                    try {
                        in.close();
                    }catch(Exception e) {
                        raiseError(e);
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    }catch(Exception e) {
                        raiseError(e);
                    }
                }
                if (conn != null) {
                    conn.disconnect();
                }
            }
        } else {
            commandResult.fail(Consts.HOST_CONNECT_FAIL);
        }

        return commandResult;
    }

    protected boolean ready() {
        String url = getURL();
        String token = getToken();
        return url != null
                && url.contains("http://")
                && url.length() > 7
                && token != null
                && !token.equals("");
    }

    public class CommandResult {
        private boolean ok;
        private String message;
        private Object data;


        public boolean OK() {
            return ok;
        }
        public String Message() {
            return message;
        }
        public Object getData() {
            return this.data;
        }

        public void success() {
            this.success(null);
        }

        public void success(Object data) {
            this.ok = true;
            this.data = data;
        }

        public void fail(String message) {
            this.ok = false;
            this.message = message;
        }
    }

    public class CommandRQ<T> {
        private String token;
        private T data;

        public void setToken(String token) {
            this.token = token;
        }
        public String getToken() {
            return token;
        }

        public void setData(T data) {
            this.data = data;
        }
        public T getData() {
            return data;
        }
    }
}
